package tjs.study.notes.dotest.proxy.bytebuddy.agentConfig;

import net.bytebuddy.agent.builder.AgentBuilder;
import net.bytebuddy.description.type.TypeDescription;
import net.bytebuddy.dynamic.DynamicType;
import net.bytebuddy.implementation.FixedValue;
import net.bytebuddy.implementation.MethodDelegation;
import net.bytebuddy.implementation.bind.annotation.RuntimeType;
import net.bytebuddy.implementation.bind.annotation.SuperCall;
import net.bytebuddy.matcher.ElementMatchers;
import net.bytebuddy.utility.JavaModule;
import tjs.study.notes.dotest.proxy.bytebuddy.service.Target;

import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.instrument.Instrumentation;
import java.lang.reflect.Method;
import java.util.concurrent.Callable;

/**
 * Created by Nicky.Tang on 2021/10/9 11:04 上午
 *
 * @since 02.12.10
 */
public class DoTestOfByteBuddyAgentConfig {

    //public static void agentmain(String options, Instrumentation ins) {//会无效
    public static void premain(String options, Instrumentation ins) {
        System.out.println("print pre main");
        demoAgent(ins);
        toStringAgent(ins);
        aopAgent(ins);
    }

    public static void demoAgent(Instrumentation ins) {
        new AgentBuilder.Default()
                .type(ElementMatchers.nameStartsWith("tjs.study.notes.dotest.proxy.bytebuddy")) // 指定需要拦截的全限定类名前缀
                .transform(new AgentBuilder.Transformer() {
                    @Override
                    public DynamicType.Builder<?> transform(DynamicType.Builder<?> builder, TypeDescription typeDescription, ClassLoader classLoader, JavaModule module) {
                        return builder.method(ElementMatchers.named("hellowWorld")).intercept(MethodDelegation.to(Target.class));//如果有多个，会按顺序执行
                    }
                }).installOn(ins);
    }

    public static void toStringAgent(Instrumentation ins) {
        new AgentBuilder.Default()
                .type(ElementMatchers.isAnnotatedWith(ToString.class))
                .transform(new AgentBuilder.Transformer() {
                    @Override
                    public DynamicType.Builder<?> transform(DynamicType.Builder<?> builder, TypeDescription typeDescription, ClassLoader classLoader, JavaModule module) {
                        return builder.method(ElementMatchers.named("toString")).intercept(FixedValue.value("test"));
                    }
                }).installOn(ins);
    }

    @Retention(RetentionPolicy.RUNTIME)
    public @interface ToString {
    }

    public static void aopAgent(Instrumentation ins) {
        new AgentBuilder.Default()
                .type(ElementMatchers.nameStartsWith("tjs.study.notes.dotest.proxy.bytebuddy")) // 指定需要拦截的全限定类名前缀
                .transform(new AgentBuilder.Transformer() {
                    @Override
                    public DynamicType.Builder<?> transform(DynamicType.Builder<?> builder, TypeDescription typeDescription, ClassLoader classLoader, JavaModule module) {
                        return builder.method(ElementMatchers.named("hellowWorld")).intercept(MethodDelegation.to(TimeInterceptor.class));
                    }
                }).installOn(ins);
    }

    public static class TimeInterceptor {
        @RuntimeType
        public static Object intercept(@net.bytebuddy.implementation.bind.annotation.Origin Method method,
                                       @SuperCall Callable<?> callable) throws Exception {
            long start = System.currentTimeMillis();
            try {
                // 原有函数执行
                return callable.call();
            } finally {
                System.out.println(method + ": took " + (System.currentTimeMillis() - start) + "ms");
            }
        }
    }
}
